package com.flow.asyncflow.core.utils.log.businesslog;


import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.flow.asyncflow.core.annotation.TableFieldDes;
import com.flow.asyncflow.core.entity.core.AsyncFlowBaseContext;
import com.flow.asyncflow.core.entity.core.AsyncFlowRequest;
import com.flow.asyncflow.core.entity.log.businesslog.AsyncFlowBusinessLogEntity;
import com.flow.asyncflow.core.entity.log.businesslog.SaveBusinessLogEntity;
import com.flow.asyncflow.core.utils.http.AsyncFlowHttpClientUtil;
import com.flow.asyncflow.core.utils.msg.AsyncFlowSendMsg;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;
import lombok.SneakyThrows;
import org.apache.commons.lang.StringUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 业务日志
 */
public class AsyncFlowBusinessLog {
    /**
     * 添加业务日志
     *
     * @param orderFlowData 上下文
     * @param logInfo       日志内容
     * @param mustRecord    是否必须记录
     */
    public static void addBusinessLog(AsyncFlowBaseContext orderFlowData, String logInfo, boolean mustRecord) {
        AsyncFlowBusinessLogEntity asyncBusinessLogEntity = new AsyncFlowBusinessLogEntity();
        asyncBusinessLogEntity.setLogInfo(logInfo);
        asyncBusinessLogEntity.setLocalDateTime(LocalDateTime.now());
        asyncBusinessLogEntity.setMustRecord(mustRecord);
        orderFlowData.getAsyncBusinessLogEntityList().add(asyncBusinessLogEntity);
    }

    /**
     * 根据实体变化自动生成业务日志
     *
     * @param t
     * @param <T>
     * @return
     */
    @SneakyThrows
    public static <T> String getLogContent(T t) {
        String logContent = "";
        Class<?> tClass = t.getClass();
        //表名称
        String tableName = "";

        Annotation[] tableMethods = tClass.getAnnotations();
        for (Annotation annotation : tableMethods) {
            //获取方法名
            if (annotation instanceof TableName) {
                tableName = ((TableName) annotation).value();
                break;
            }
        }
        if (StringUtils.isBlank(tableName)) {
            throw new IllegalAccessException("表名为空，请检查当前实体是否有@TableName注解");
        }
        String tableIdName = "";
        long tableId = -1L;
        Field[] field;
        //获取所有字段
        field = tClass.getDeclaredFields();

        Map<String, String> fieldMap = new HashMap<>();
        for (Field value : field) {
            if (tableId >= 0) {
                break;
            }
            Annotation[] ids = value.getAnnotations();
            for (Annotation annotation : ids) {
                value.setAccessible(true);


                //获取方法名
                if (annotation instanceof TableId) {
                    //获取属性的名字
                    String name = value.getName();
                    //将属性名字的首字母大写
                    name = name.replaceFirst(name.substring(0, 1), name.substring(0, 1).toUpperCase());
                    //整合出 get() 属性这个方法
                    Method m = tClass.getMethod("get" + name);
                    Object tableIdObj = m.invoke(t);
                    if (tableIdObj == null) {
                        tableId = 0L;

                    } else {
                        tableId = (long) tableIdObj;
                    }
                    tableIdName = value.getName();
                    break;
                }

            }
        }

        StringBuilder stringBuilder = new StringBuilder();
        String operatorType = "";
        if (tableId > 0) {
            operatorType="【修改】";
        }
        else {
            operatorType="【新增】";
        }
        stringBuilder.append(String.format("<p style='font-weight:bold;color:green;'>======%s======%s=====</p>",tableName,operatorType));
        stringBuilder.append("<table width='600px' style='table-layout: fixed;'>");
        stringBuilder.append("<tr style='text-align:center;'>");
        stringBuilder.append("<td style='border:1px solid;width:20%;'><span style='font-weight:bold;'>属性</span></td>");
        stringBuilder.append("<td style='border:1px solid;width:40%;'><span style='font-weight:bold;'>旧值</span></td>");
        stringBuilder.append("<td style='border:1px solid;width:40%;'><span style='font-weight:bold;'>新值</span></td>");
        stringBuilder.append("</tr>");
        if (tableId == 0) {
            for (Field value : field) {

                //获取属性的名字
                String fieldName = value.getName();
                //将属性名字的首字母大写
                fieldName = fieldName.replaceFirst(fieldName.substring(0, 1), fieldName.substring(0, 1).toUpperCase());
                //整合出 get() 属性这个方法
                Method fieldM = tClass.getMethod("get" + fieldName);
                Object fieldObj = fieldM.invoke(t);
                if (fieldObj != null) {
                    String dataBaseFieldName = value.getName();
                    //判断是否存在注解，存在字段注解，拿注解中真实的数据库字段名
                    Annotation[] tableFiled = value.getAnnotations();
                    String tableFieldDes = "";
                    if (tableFiled != null && tableFiled.length > 0) {
                        for (Annotation annotation : tableFiled) {
                            if (annotation instanceof TableField) {
                                dataBaseFieldName = ((TableField) annotation).value();
                            }
                            if (annotation instanceof TableFieldDes) {
                                tableFieldDes = ((TableFieldDes) annotation).name();
                            }
                        }
                    }

                    String msg = String.format("<tr style='text-align:center;'><td style='border:1px solid;'>%s</td><td style='border:1px solid;'>%s</td><td style='border:1px solid;'>%s</td></tr>"
                            , tableFieldDes + "[" + dataBaseFieldName + "]"
                            , "null"
                            , fieldObj
                    );
                    stringBuilder.append(msg);
                }
            }
        } else {
            //Map<String, Object> updateChangeValues;
            Map<String, Map<Object, Object>> changeValuesV2 = new HashMap<>();
            Field fieldChangeValues;
            // 表示获取指定的一个公共的字段，包括继承的
            fieldChangeValues = tClass.getField("changeValuesV2");
            //获取属性的名字
            String name = fieldChangeValues.getName();
            //将属性名字的首字母大写
            name = name.replaceFirst(name.substring(0, 1), name.substring(0, 1).toUpperCase());
            //整合出 get() 属性这个方法
            Method m = tClass.getMethod("get" + name);
            //调用这个整合出来的get方法，强转成自己需要的类型
            //updateChangeValues = (Map<String, Object>) m.invoke(t);
            changeValuesV2 = (Map<String, Map<Object, Object>>) m.invoke(t);
            for (Field value : field) {
                //获取属性的名字
                String fieldName = value.getName();
                //将属性名字的首字母大写
                fieldName = fieldName.replaceFirst(fieldName.substring(0, 1), fieldName.substring(0, 1).toUpperCase());
                //整合出 get() 属性这个方法
                Method fieldM = tClass.getMethod("get" + fieldName);
                Object fieldObj = fieldM.invoke(t);

                if (fieldObj != null) {
                    String dataBaseFieldName = value.getName();
                    String tableFieldDes = "";
                    //判断是否存在注解，存在字段注解，拿注解中真实的数据库字段名
                    Annotation[] tableFiled = value.getAnnotations();
                    if (tableFiled != null) {
                        for (Annotation annotation : tableFiled) {
                            if (annotation instanceof TableField) {
                                dataBaseFieldName = ((TableField) annotation).value();
                            }
                            if (annotation instanceof TableFieldDes) {
                                tableFieldDes = ((TableFieldDes) annotation).name();
                            }
                        }
                    }
                    if (!changeValuesV2.containsKey(dataBaseFieldName)) {
                        //变化字段中没有这个属性
                        continue;
                    }
                    Map<Object, Object> changeValue = changeValuesV2.get(dataBaseFieldName);

                    String msg = String.format("<tr style='text-align:center;'><td style='border:1px solid;'>%s</td><td style='border:1px solid;'>%s</td><td style='border:1px solid;'>%s</td></tr>"
                            , tableFieldDes + "[" + dataBaseFieldName + "]"
                            , changeValue.get(fieldObj)
                            , fieldObj
                    );
                    stringBuilder.append(msg);
                }
            }
        }
        stringBuilder.append("</table>");
        logContent = stringBuilder.toString();
        return logContent;
    }


    /**
     * 添加业务日志
     *
     * @param asyncFlowRequest 请求
     * @param asyncFlowData    上下文
     * @param msg              日志
     * @param allNodeIsSuccess 节点状态
     */
    public static void saveBusinessLog(AsyncFlowRequest asyncFlowRequest, AsyncFlowBaseContext asyncFlowData, String msg, boolean allNodeIsSuccess) {
        try {
            StringBuilder stringBuilder = new StringBuilder();
            String reason;
            if (!allNodeIsSuccess) {
                reason = "失败原因：" + msg;
                AsyncFlowBusinessLog.addBusinessLog(asyncFlowData, reason, true);
            }
            if (asyncFlowData.getAsyncBusinessLogEntityList().isEmpty()) {
                return;
            }

            if (StringUtils.isBlank(asyncFlowRequest.getBusinessSerialId())) {
                return;
            }
            //基础日志内容
            //String logInfo = "【" + asyncFlowRequest.getSourceDes() + "】触发【" + asyncFlowRequest.getReqTypeEnumMsg() + "】【" + (allNodeIsSuccess ? "成功" : "失败") + "】";

            String logInfo = "【" + asyncFlowRequest.getReqTypeEnumMsg() + "】【" + (allNodeIsSuccess ? "成功" : "失败") + "】";
            for (AsyncFlowBusinessLogEntity orderLogEntity : asyncFlowData.getAsyncBusinessLogEntityList().stream().sorted(Comparator.comparing(AsyncFlowBusinessLogEntity::getLocalDateTime)).collect(Collectors.toList())) {
                //在失败的情况下，仅仅记录必须要记录的日志（非必须的不记录-跳过）
                if (!allNodeIsSuccess && !orderLogEntity.isMustRecord()) {
                    continue;
                }
                stringBuilder.append(orderLogEntity.getLogInfo()).append("<Br/>");
            }
            String log = stringBuilder + logInfo;
            SaveBusinessLogEntity saveBusinessLogEntity = new SaveBusinessLogEntity();
            saveBusinessLogEntity.setBusinessSerialId(asyncFlowRequest.getBusinessSerialId());
            if (StringUtils.isBlank(asyncFlowRequest.getOperateName())) {
                asyncFlowRequest.setOperateName("0");
            }
            if (StringUtils.isBlank(asyncFlowRequest.getOperateNo())) {
                asyncFlowRequest.setOperateNo("0");
            }
            saveBusinessLogEntity.setOperateName(asyncFlowRequest.getOperateName());
            saveBusinessLogEntity.setOperateNo(asyncFlowRequest.getOperateNo());
            saveBusinessLogEntity.setLogInfo(log);
            saveBusinessLogEntity.setLogTime(LocalDateTimeUtil.format(asyncFlowRequest.getRequesterTime(), DatePattern.NORM_DATETIME_PATTERN));
            String result = AsyncFlowHttpClientUtil.post(asyncFlowData.getAsyncFlowInfo().getBusinessLogUrl(), saveBusinessLogEntity, String.class);
            JSONObject jsonObject = JSONObject.parseObject(result);
            if (jsonObject != null) {
                if (jsonObject.toString().contains("Code"))
                {
                    int code = jsonObject.getShort("Code");
                    if (code != 200) {
                        String errorMsg = jsonObject.getString("Msg");
                        AsyncFlowSendMsg.sendAlarmMsg(asyncFlowRequest, errorMsg, "保存业务日志", asyncFlowData.getAsyncFlowInfo());
                    }
                }
                else if (jsonObject.toString().contains("code"))
                {
                    int code = jsonObject.getShort("code");
                    if (code != 200) {
                        String errorMsg = jsonObject.getString("msg");
                        AsyncFlowSendMsg.sendAlarmMsg(asyncFlowRequest, errorMsg, "保存业务日志", asyncFlowData.getAsyncFlowInfo());
                    }
                }
            }
        } catch (Exception e) {
            String s = AsyncFlowSendMsg.buildErrorMsg(asyncFlowRequest, e, "保存业务日志", asyncFlowData.getAsyncFlowInfo());
            AsyncFlowSendMsg.sendQYWXMsg(asyncFlowData.getAsyncFlowInfo().getFlowMaintainName(), s, asyncFlowData.getAsyncFlowInfo().getNodeArmUrl());
        }


    }
}
